#pragma once

#include "log.hpp"
#include <iostream>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>

using std::string;
using std::cout;
using std::endl;

// 通信服务
static void service(int sock, const string& clientip, const uint16_t& clientport)
{
    // cout << "执行service(通信)" << endl;
    char buffer[1024];
    while(true)
    {
        // 网络通信 可以直接使用read/write
        ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
        if(s > 0) {// 成功读取
            buffer[s] = 0;
            cout << clientip << " : " << clientport << "# " << buffer << endl;
        }else if (s == 0){ // 对端关闭了连接
            logMessage(NORMAL, "%s:%d shutdown, metoo", clientip.c_str(), clientport);
            break;
        }else{ // 错误
            logMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        // 读取成功 将buffer内容写入sock（回显）
        write(sock, buffer, strlen(buffer));
    }
    close(sock);
}

class TcpServer
{
private:
    // 定义服务器监听连接请求的最大队列长度
    const static int gbacklog = 20;

public:
    TcpServer(uint16_t port, string ip = ""): _port(port), _ip(ip), listensock(-1) // 设定缺省值
    {}

    // 初始化服务器
    void initServer()
    {
        // 1. 创建socket —— 进程、文件方面
        listensock = socket(AF_INET, SOCK_STREAM, 0); // ipv4协议，套接字类型，协议类型
        if(listensock < 0) // 创建套接字失败
        {
            logMessage(FATAL, "%d : %s", errno, strerror(errno));
            exit(2); // 退出进程
        }
        logMessage(NORMAL, "create socket success, sock: %d", listensock); // 创建成功，输出信息

        // 2. bind —— 网络、文件方面
        struct sockaddr_in local; // 表示ipv4地址
        memset(&local, 0, sizeof(local)); // 初始化
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());

        // 3. 设置监听状态
        // TCP面向连接，正式通信前，应先建立连接
        if(listen(listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen error: %d:%s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success.");
    }

    void startServer()
    {
        // cout << "执行start(启动)" << endl;
        signal(SIGCHLD, SIG_IGN); // 此signal ：v2 多线程
        while(true)
        {
            // 4. 获取连接
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            int servicesock = accept(listensock, (struct sockaddr*)&src, &len);
            if(servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            logMessage(NORMAL, "accept success, sock: %d", servicesock);
            // 获取连接成功
            uint16_t client_port = ntohs(src.sin_port);
            string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success, servicesock: %d| %s : %d |\n", servicesock, client_ip.c_str(), client_port);
            // 开始通信：
            // v1: 单进程循环
            // service(servicesock, client_ip, client_port);

            // v2: 多进程
            // 子进程用于给新的连接提供服务(service)，父进程继续执行循环接收连接
            pid_t id = fork();
            assert(id != -1);
            if(id == 0)
            {
                // 子进程: 用于提供服务，无需监听socket
                close(listensock);
                service(servicesock, client_ip, client_port);
                exit(0); // 此时僵尸状态
            }
            close(servicesock); // 父进程不提供服务
        }
    }

    ~TcpServer(){}

private:
    uint16_t _port; // 端口号
    string _ip; // ip地址
    int listensock; // 套接字
};